package org.copper.utils
{
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.filters.ColorMatrixFilter;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	public final class GraphicsUtil
	{
		/**
		 * return hexodecimal representation of given color.
		 */
		public static function RGBtoHex(red:Number, green:Number, blue:Number, alpha:Number = 100):uint
		{
			return (new ColorTransform(0, 0, 0, 0, red, green, blue, alpha)).color;
		}
		
		/**
		 * returns array withs 4 members representing RGB and Alpha.
		 * @param       value:uint   original color
		 * @return      Array
		 */
		public static function HexToRGB(color:uint):Array
		{
			return [(color >> 16 & 0xFF), (color >> 8 & 0xFF), (color & 0xFF), (color >> 24 & 0xFF)];
		}
		
		/**
		 * sets brightness value available are -100 ~ 100 @default is 0
		 * @param       value:int   brightness value
		 * @return      ColorMatrixFilter
		 */
		public static function getBrightnessFilter(value:Number):ColorMatrixFilter
		{
			return new ColorMatrixFilter([[1, 0, 0, 0, value], [0, 1, 0, 0, value],[0, 0, 1, 0, value],[0, 0, 0, 1, 0]]);
		}
		
		/**
		 * sets contrast value available are -100 ~ 100 @default is 0
		 * @param       value:int   contrast value
		 * @return      ColorMatrixFilter
		 */
		public static function getContrastFilter(value:Number):ColorMatrixFilter
		{
			value /= 100;
			const s: Number = value + 1;
			const o : Number = 128 * (1 - s);
			return new ColorMatrixFilter([[s, 0, 0, 0, o], [0, s, 0, 0, o], [0, 0, s, 0, o], [0, 0, 0, 1, 0]]);
		}
		
		/**
		 * sets saturation value available are -100 ~ 100 @default is 0
		 * @param       value:int   saturation value
		 * @return      ColorMatrixFilter
		 */
		public static function getSaturationFilter(value:Number):ColorMatrixFilter
		{
			const lumaR:Number = 0.212671;
			const lumaG:Number = 0.71516;
			const lumaB:Number = 0.072169;
			const v:Number = (value/100) + 1;
			const i:Number = (1 - v);
			const r:Number = (i * lumaR);
			const g:Number = (i * lumaG);
			const b:Number = (i * lumaB);
			return new ColorMatrixFilter([[(r + v), g, b, 0, 0], [r, (g + v), b, 0, 0], [r, g, (b + v), 0, 0], [0, 0, 0, 1, 0]]);
		}
		
		public static function intencity(color:uint):Number
		{
			const r:Number = validateColorCompenent(color >> 16 & 0xFF);
			const g:Number = validateColorCompenent(color >> 8 & 0xFF);
			const b:Number = validateColorCompenent(color & 0xFF);
			return Math.sqrt((r*r) + (g*g) + (b*b));
		}
		
		public static function setIntencity(color:uint, Intencity:Number):uint
		{
			const coef:Number = (validateIntencity(Intencity)/intencity(color));
			const r:Number = validateColorCompenent((color >> 16 & 0xFF) * coef);
			const g:Number = validateColorCompenent((color >> 8 & 0xFF) * coef);
			const b:Number = validateColorCompenent((color & 0xFF) * coef);
			return RGBtoHex(r, g, b);
		}
		
		public static function getBetweenColourByPercent(percent:Number, highColor:uint, lowColor:uint):uint 
		{
			var r:uint = highColor >> 16;
			var g:uint = highColor >> 8 & 0xFF;
			var b:uint = highColor & 0xFF;
			
			r += ((lowColor >> 16) - r)       * percent;
			g += ((lowColor >> 8 & 0xFF) - g) * percent;
			b += ((lowColor & 0xFF) - b)      * percent;
			
			return (r << 16 | g << 8 | b);
		}
		
		public static function getHarmonies(color:uint, weight:Number):Array
		{
			const red:uint = color >> 16;
			const green:uint = (color ^ (red << 16)) >> 8;
			const blue:uint = (color ^ (red << 16)) ^ (green << 8);
			
			return [
				RGBtoHex(red    , green  , weight ), 
				RGBtoHex(red    , weight , blue   ), 
				RGBtoHex(weight , green  , blue   ),
				RGBtoHex(red    , weight , weight ), 
				RGBtoHex(weight , green  , weight ), 
				RGBtoHex(weight , weight , blue   )
			];
		}
		
		public static function createBitmapData(displayObject:DisplayObject):BitmapData
		{
			const bounds 	 :Rectangle   = displayObject.getRect(displayObject);
			const mtxShift   :Matrix      = new Matrix(1,0,0,1, -bounds.x, -bounds.y);
			const resBitmap  :BitmapData  = new BitmapData(bounds.width, bounds.height, true, 0);
			resBitmap.draw(displayObject, mtxShift);
			return resBitmap;
		}
		
		public static function createScaledBitmapData(disObj:DisplayObject, scale:Number):BitmapData
		{
			const bounds 	 :Rectangle   = disObj.getRect(disObj);
			bounds.width = bounds.width * scale;
			bounds.height = bounds.height * scale;
			const mtxShift   :Matrix      = new Matrix(1,0,0,1, -bounds.x, -bounds.y);
			mtxShift.scale(scale, scale);
			const resBitmap  :BitmapData  = new BitmapData(bounds.width, bounds.height, true, 0);
			resBitmap.draw(disObj, mtxShift);
			return resBitmap;
		}
		
		public static function createScaledXYBitmapData(disObj:DisplayObject, scaleX:Number, scaleY:Number):BitmapData
		{
			const bounds 	 :Rectangle   = disObj.getRect(disObj);
			bounds.width = bounds.width * scaleX;
			bounds.height = bounds.height * scaleY;
			const mtxShift   :Matrix      = new Matrix(1,0,0,1, -bounds.x, -bounds.y);
			mtxShift.scale(scaleX, scaleY);
			const resBitmap  :BitmapData  = new BitmapData(bounds.width, bounds.height, true, 0);
			resBitmap.draw(disObj, mtxShift);
			return resBitmap;
		}
		
		public static function createSubBitmapData(displayObject:DisplayObject, bounds:Rectangle = null):BitmapData
		{
			if (bounds == null)
			{
				bounds = displayObject.getRect(displayObject);
			}
			
			const ans        :BitmapData  = new BitmapData(bounds.width, bounds.height, true, 0);
			const matrix:Matrix = new Matrix(1,0,0,1, -bounds.x, -bounds.y);
			ans.draw(displayObject, matrix);
			return ans;
		}
		
		
		public static function roundCorners(dObj:DisplayObject, indention:Number):BitmapData
		{
			const canvas:Sprite = new Sprite();
			const msk:Sprite = new Sprite();
			const obj:Sprite = new Sprite();
			const gr:Graphics = msk.graphics;
			obj.addChild(dObj);
			
			//..................mask................
			const width:Number = dObj.width;
			const height:Number = dObj.height;
			
			const point1:Point = new Point(indention, indention);
			const point2:Point = new Point(width - indention, indention);
			const point3:Point = new Point(width - indention, height - indention);
			const point4:Point = new Point(indention, height - indention);
			
			
			gr.beginFill(0);
			gr.drawRect(point1.x, point1.y, point3.x - point1.x, point3.y - point1.y);
			gr.endFill();
			gr.beginFill(0);
			gr.drawCircle(point1.x, point1.y, indention);
			gr.drawCircle(point2.x, point2.y, indention);
			gr.drawCircle(point3.x, point3.y, indention);
			gr.drawCircle(point4.x, point4.y, indention);
			gr.endFill();
			gr.beginFill(0);
			gr.drawRect(0, indention, indention, point4.y - indention);
			gr.drawRect(indention, 0, point3.x - indention, indention);
			gr.drawRect(indention, point3.y, point3.x - indention, indention);
			gr.drawRect(point3.x, indention, indention, point4.y - indention);
			gr.endFill();
			//..................mask................
			
			
			canvas.addChild(obj);
			canvas.addChild(msk);
			obj.cacheAsBitmap = true;
			msk.cacheAsBitmap = true;
			obj.mask = msk;
			
			return createBitmapData(canvas);
		}
		
		
		//................................................PRIVATE.........................................................
		private static function validateColorCompenent(comp:Number):Number
		{
			return comp < 0?0:comp > 255?255:comp;
		}
		
		private static function validateIntencity(intenc:Number):Number
		{
			return intenc < 0?0:intenc > MAX_INTENCITY?MAX_INTENCITY:intenc;
		}
		
		public static const MAX_INTENCITY:Number = Math.sqrt((255*255) + (255*255) + (255*255));
		private static const ZERO:Number = 0;
		
	}
}